
/**
 * 
 */
 let gfx = cc['gfx'];
 export class MeshUtils {
     public static instance = new MeshUtils();
 
     _offset = cc.v2(0, 0);
     get offset() {
         return this._offset;
     }
     set offset(offset: cc.Vec2) {
         this._offset = offset;
     }
 
     _spriteFrame: cc.SpriteFrame = null;
     get meshSpriteFrame() {
         return this._spriteFrame;
     }
     set meshSpriteFrame(spriteFrame: cc.SpriteFrame) {
         this._spriteFrame = spriteFrame;
     }
 
     /**自定义图片网格顶点 */
     public customMeshNode(sp: cc.SpriteFrame, vertexes: Array<cc.Vec2>): cc.Node {
         this.meshSpriteFrame = sp;
         // let spriteFrame = this.meshSpriteFrame;
         // let spriteFrameWidth = spriteFrame.getOriginalSize().width;
         // let spriteFrameHeight = spriteFrame.getOriginalSize().height;
         let piece = new cc.Node('piece');
         this.init(piece);
         this.setSpriteFrame(piece, sp);
         this.setMesh(piece, vertexes);
 
         _G['piece'] = piece;
         return piece;
     }
 
     /**把一张图片拆成4块返回节点数组 */
     public createQuadMeshNodes(sp: cc.SpriteFrame): Array<cc.Node> {
         let pieces = [];
 
         this.meshSpriteFrame = sp;
         /**返回四均分顶点 */
         let quadVertexes = () => {
             let spriteFrame = this.meshSpriteFrame;
             let width = spriteFrame.getOriginalSize().width;
             let height = spriteFrame.getOriginalSize().height;
             return [
                 // 1
                 [cc.v2(0, 0), cc.v2(-width / 2, 0), cc.v2(-width / 2, height / 2), cc.v2(0, height / 2)],
                 // 2
                 [cc.v2(0, 0), cc.v2(0, height / 2), cc.v2(width / 2, height / 2), cc.v2(width / 2, 0)],
                 // 3
                 [cc.v2(0, 0), cc.v2(0, -height / 2), cc.v2(-width / 2, -height / 2), cc.v2(-width / 2, 0)],
                 // 4
                 [cc.v2(0, 0), cc.v2(width / 2, 0), cc.v2(width / 2, -height / 2), cc.v2(0, -height / 2)],
             ];
         }
         let list = quadVertexes();
 
         let spriteFrame = this.meshSpriteFrame;
         // let spriteFrameWidth = spriteFrame.getOriginalSize().width;
         // let spriteFrameHeight = spriteFrame.getOriginalSize().height;
         // let offsets = [
         //     cc.v2(0.2 * spriteFrameWidth, -0.2 * spriteFrameHeight),
         //     cc.v2(-0.2 * spriteFrameWidth, -0.2 * spriteFrameHeight),
         //     cc.v2(0.2 * spriteFrameWidth, 0.2 * spriteFrameHeight),
         //     cc.v2(-0.2 * spriteFrameWidth, 0.2 * spriteFrameHeight),
         // ]
         for (let i = 0; i < 4; i++) {
             let piece = new cc.Node('piece');
             this.init(piece);
             this.setSpriteFrame(piece, sp);
             // this.offset = offsets[i];
             this.setMesh(piece, list[i]);
             pieces.push(piece);
         }
         return pieces;
     }
 
 
     /**初始化meshRenderer组件 清理掉多余的渲染组件*/
     init(node: cc.Node) {
         node.removeComponent(cc.RenderComponent);
         node.removeComponent(cc.MeshRenderer);
         node['_meshRenderer'] = node.addComponent(cc.MeshRenderer);
         node['_meshRenderer'].enableAutoBatch = false;
         node['_meshRenderer'].mesh = null;
 
         let builtinMaterial = new cc.Material();
         builtinMaterial.copy(cc.Material.getInstantiatedBuiltinMaterial("unlit", this));   //getBuiltinMaterial
         node['_meshRenderer'].setMaterial(0, builtinMaterial);
         // debugger
     }
 
     setSpriteFrame(node: cc.Node, spriteFrame: cc.SpriteFrame) {
         if (node['_meshRenderer']) {
             let material = node['_meshRenderer']._materials[0];
             if (material) {
                 // Reset material
                 let texture = spriteFrame.getTexture();
                 material.define("USE_DIFFUSE_TEXTURE", true);
                 material.setProperty('diffuseTexture', texture);
             }
         }
     }
 
     /**设置网格数据 */
     setMesh(node: cc.Node, vertexes: Array<cc.Vec2>) {
         // 精灵图长宽
         let spriteFrame = this.meshSpriteFrame;
         let spriteFrameWidth = spriteFrame.getOriginalSize().width;
         let spriteFrameHeight = spriteFrame.getOriginalSize().height;
         // 精灵图uv
         let l = spriteFrame['uv'][0],
             t = spriteFrame['uv'][5],
             r = spriteFrame['uv'][6],
             b = spriteFrame['uv'][3];
         let isRotated = spriteFrame.isRotated();
         let uvOffset = new cc.Vec4(l, t, r, b);
 
         // 计算uv
         // console.log('vertex1', vertexes)
         let uvs = new Array();
         for (let i = 0; i < vertexes.length; i++) {
             let vertex = vertexes[i];
             let u = (vertex.x + spriteFrameWidth / 2) / spriteFrameWidth;
             let v = 1 - ((vertex.y + spriteFrameHeight / 2) / spriteFrameHeight);
             let v_uv0 = cc.v2(u, v);
             if (isRotated) {
                 u = (vertex.x + spriteFrameWidth / 2) / spriteFrameWidth;
                 v = ((vertex.y + spriteFrameHeight / 2) / spriteFrameHeight);
                 v_uv0 = cc.v2(v, u);
             }
             let uv_x = uvOffset.x + v_uv0.x * (uvOffset.z - uvOffset.x);
             let uv_y = uvOffset.y + v_uv0.y * (uvOffset.w - uvOffset.y);
             let realUV = cc.v2(uv_x, uv_y);
             // if (spriteFrame.isRotated()) {
             //     u = (vertex.x + this.offset.x * spriteFrameWidth) / spriteFrameWidth;
             //     v = ((vertex.y + this.offset.y * spriteFrameHeight) / spriteFrameHeight);
             //     v_uv0 = cc.v2(v, u);
             //     uv_x = uvOffset.x + v_uv0.x * (uvOffset.z - uvOffset.x);
             //     uv_y = uvOffset.y + v_uv0.y * (uvOffset.w - uvOffset.y);
             //     realUV = cc.v2(uv_x, uv_y);
             // }
             uvs.push(realUV);
         }
 
         let count = 0;
         let totalCrossMultiplica = 0;
         for (let i = 0; i < vertexes.length - 2; i++) {
             let p1 = vertexes[i];
             let p2 = vertexes[i + 1];
             let p3 = vertexes[i + 2];
             let v1 = p2.sub(p1);
             let v2 = p3.sub(p2);
             totalCrossMultiplica += v1.cross(v2);
         }
         if (vertexes.length >= 3) {
             // 计算顶点索引 
             let ids = [];
             const vertexesCopy = [].concat(vertexes);
             // 多边形切割，未实现相交的复杂多边形，确保顶点按顺序且围成的线不相交
             let index = 0, rootIndex = -1;
             let isTuPoint = (crossMultiplica: number) => {
                 if (totalCrossMultiplica > 0) {
                     if (crossMultiplica > 0) {
                         return true;
                     } else {
                         return false;
                     }
                 } else {
                     if (crossMultiplica < 0) {
                         return true;
                     } else {
                         return false;
                     }
                 }
             }
             while (vertexesCopy.length > 3 && count < 10000) {
                 count++;
                 const p1 = vertexesCopy[index];
                 const p2 = vertexesCopy[(index + 1) % vertexesCopy.length];
                 const p3 = vertexesCopy[(index + 2) % vertexesCopy.length];
 
                 const v1 = p2.sub(p1);
                 const v2 = p3.sub(p2);
                 let crossMultiplica = v1.cross(v2);
                 let isTu = isTuPoint(crossMultiplica);
                 if (isTu) {
                     // 是凸点
                     let isIn = false;
                     for (const p_t of vertexesCopy) {
                         if (p_t !== p1 && p_t !== p2 && p_t !== p3 && this._testInTriangle(p_t, p1, p2, p3)) {
                             // 其他点在三角形内
                             isIn = true;
                             break;
                         }
                     }
                     if (!isIn) {
                         // 切耳朵，是凸点，且没有其他点在三角形内
                         ids = ids.concat([vertexesCopy.indexOf(p1), vertexesCopy.indexOf(p2), vertexesCopy.indexOf(p3)]);
                         vertexesCopy.splice(vertexesCopy.indexOf(p2), 1);
                         rootIndex = index;
                     } else {
                         index = (index + 1) % vertexesCopy.length;
                         if (index === rootIndex) {
                             cc.log('循环一圈未发现');
                             break;
                         }
                     }
                 } else {
                     index = (index + 1) % vertexesCopy.length;
                     if (index === rootIndex) {
                         cc.log('循环一圈未发现');
                         break;
                     }
                 }
                 // 感谢 @可有 修复
                 if (index > (vertexesCopy.length - 1)) index = (vertexesCopy.length - 1);
             }
             ids = ids.concat(vertexesCopy.map(v => { return vertexes.indexOf(v) }));
             /**设置网格数据 */
             let mesh = new cc.Mesh();
             let vertexFmt = new gfx.VertexFormat([
                 { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
                 { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
             ])
             // 计算完uv后再进行顶点的偏移计算
             for (let i of vertexes) {
                 i.x += this.offset.x;
                 i.y += this.offset.y;
             }
             // console.error('设置网格成功 vertexes', vertexes);
             // console.error('设置网格成功 uvs', uvs);
             // console.error('设置网格成功 ids', ids);
             mesh.init(vertexFmt, vertexes.length, true);
             mesh.setVertices(gfx.ATTR_POSITION, vertexes)
             mesh.setVertices(gfx.ATTR_UV0, uvs)
             mesh.setIndices(ids)
             node['_meshRenderer'].mesh = mesh;
         }
     }
 
 
     // 判断一个点是否在三角形内
     _testInTriangle(point, triA, triB, triC) {
         let AB = triB.sub(triA), AC = triC.sub(triA), BC = triC.sub(triB), AD = point.sub(triA), BD = point.sub(triB);
         return (AB.cross(AC) >= 0 !== AB.cross(AD) < 0)  // D,C 在AB同同方向
             && (AB.cross(AC) >= 0 !== AC.cross(AD) >= 0) // D,B 在AC同同方向
             && (BC.cross(AB) > 0 !== BC.cross(BD) >= 0); // D,A 在BC同同方向
     }
 
 }